package com.vinda.ucvcamera;

import static io.agora.rtc2.video.VideoCanvas.RENDER_MODE_FIT;
import static io.agora.rtc2.video.VideoEncoderConfiguration.STANDARD_BITRATE;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Matrix;
import android.graphics.SurfaceTexture;
import android.hardware.usb.UsbDevice;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.text.TextUtils;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceView;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.Toast;

import com.serenegiant.common.BaseActivity;
import com.serenegiant.usb.CameraDialog;
import com.serenegiant.usb.USBMonitor;
import com.serenegiant.usb.USBMonitor.OnDeviceConnectListener;
import com.serenegiant.usb.USBMonitor.UsbControlBlock;
import com.serenegiant.usb.UVCCamera;
import com.serenegiant.usbcameracommon.UVCCameraHandler;
import com.serenegiant.usbcameracommon.UvcCameraDataCallBack;
import com.serenegiant.widget.CameraViewInterface;
import com.serenegiant.widget.UVCCameraTextureView;
import com.yuan.camera.R;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;

import io.agora.base.JavaI420Buffer;
import io.agora.base.NV12Buffer;
import io.agora.base.NV21Buffer;
import io.agora.base.TextureBufferHelper;
import io.agora.base.VideoFrame;
import io.agora.base.internal.video.YuvHelper;
import io.agora.rtc2.ChannelMediaOptions;
import io.agora.rtc2.Constants;
import io.agora.rtc2.IRtcEngineEventHandler;
import io.agora.rtc2.RtcConnection;
import io.agora.rtc2.RtcEngine;
import io.agora.rtc2.RtcEngineConfig;
import io.agora.rtc2.RtcEngineEx;
import io.agora.rtc2.gl.EglBaseProvider;
import io.agora.rtc2.video.VideoCanvas;
import io.agora.rtc2.video.VideoEncoderConfiguration;

/**
 * 显示多路摄像头
 */
public class MainActivity extends BaseActivity implements CameraDialog.CameraDialogParent {
    private static final boolean DEBUG = true;
    private static final String TAG = "MainActivity";

    private static final float[] BANDWIDTH_FACTORS = {0.5f, 0.5f};

    // for accessing USB and USB camera
    private USBMonitor mUSBMonitor;

    private UVCCameraHandler mHandlerFirst;
    private CameraViewInterface mUVCCameraViewFirst;
    private ImageButton mCaptureButtonFirst;
    private Surface mFirstPreviewSurface;

    private UVCCameraHandler mHandlerSecond;
    private CameraViewInterface mUVCCameraViewSecond;
    private ImageButton mCaptureButtonSecond;
    private Surface mSecondPreviewSurface;

    private UVCCameraHandler mHandlerThird;
    private CameraViewInterface mUVCCameraViewThird;
    private ImageButton mCaptureButtonThird;
    private Surface mThirdPreviewSurface;

    private UVCCameraHandler mHandlerFourth;
    private CameraViewInterface mUVCCameraViewFourth;
    private ImageButton mCaptureButtonFourth;
    private Surface mFourthPreviewSurface;

    private UVCCameraHandler mHandlerFifth;
    private CameraViewInterface mUVCCameraViewFifth;
    private ImageButton mCaptureButtonFifth;
    private Surface mFifthPreviewSurface;


    private UVCCameraHandler mHandlerSixth;
    private CameraViewInterface mUVCCameraViewSixth;
    private ImageButton mCaptureButtonSixth;
    private Surface mSixthPreviewSurface;


    //声网集成控件
    private EditText etChannelName;
    private Button btnAdd,btnTrack;
    private RtcEngineEx mRtcEngine;
    private FrameLayout flLocal;
    private int myUid;
    private volatile boolean joined = false;
    private VideoReportLayout[] flVideoContainer;
    private final List<Integer> videoTrackIds = new ArrayList<>();
    private final List<RtcConnection> connections = new ArrayList<>();

    private byte[] mData;
    private int mWidth;
    private int mHeight;
    private byte[] mData1;
    private int mWidth1;
    private int mHeight1;
    private boolean isFirst = true;
    private boolean isFirst1 = true;
    private int videoTrack;
    private int videoTrack1;
    // 填写声网控制台中生成的临时 Token
    private String token = "";
    //声网权限申请
    private static final int PERMISSION_REQ_ID = 22;
    private static final String[] REQUESTED_PERMISSIONS = {
            Manifest.permission.RECORD_AUDIO,
            Manifest.permission.CAMERA,
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE
    };
    private boolean checkSelfPermission(String permission, int requestCode) {
        if (ContextCompat.checkSelfPermission(this, permission) !=
                PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, REQUESTED_PERMISSIONS, requestCode);
            return false;
        }
        return true;
    }

    private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() {
        @Override
        public void onError(int err) {
            Log.w(TAG, String.format("onError code %d message %s", err, RtcEngine.getErrorDescription(err)));
        }

        @Override
        public void onLeaveChannel(RtcStats stats) {
            super.onLeaveChannel(stats);
            Log.i(TAG, String.format("local user %d leaveChannel!", myUid));
        }

        @Override
        public void onJoinChannelSuccess(String channel, int uid, int elapsed) {
            Log.i(TAG, String.format("onJoinChannelSuccess channel %s uid %d", channel, uid));
            myUid = uid;
            joined = true;
        }

        @Override
        public void onUserJoined(int uid, int elapsed) {
            super.onUserJoined(uid, elapsed);
            Log.i(TAG, "onUserJoined->" + uid);
            /**Check if the context is correct*/
            Context context = getBaseContext();
            if (context == null) {
                return;
            }

            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    /**Display remote video stream*/
                    View videoView = createVideoView(uid);
                    // Setup remote video to render
                    mRtcEngine.setupRemoteVideo(new VideoCanvas(videoView, RENDER_MODE_FIT, uid));
                }
            });
        }

        @Override
        public void onUserOffline(int uid, int reason) {
            Log.i(TAG, String.format("user %d offline! reason:%d", uid, reason));
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    /**Clear render view
                     Note: The video will stay at its last frame, to completely remove it you will need to
                     remove the SurfaceView from its parent*/
                    resetVideoLayout(uid);
                }
            });
        }
        @Override
        public void onRemoteVideoStats(RemoteVideoStats stats) {
            super.onRemoteVideoStats(stats);
            VideoReportLayout videoLayoutByUid = getVideoLayoutByUid(stats.uid);
            if (videoLayoutByUid != null) {
                videoLayoutByUid.setRemoteVideoStats(stats);
            }
        }

        @Override
        public void onRemoteAudioStats(RemoteAudioStats stats) {
            super.onRemoteAudioStats(stats);
            VideoReportLayout videoLayoutByUid = getVideoLayoutByUid(stats.uid);
            if (videoLayoutByUid != null) {
                videoLayoutByUid.setRemoteAudioStats(stats);
            }
        }
    };

    private View createVideoView(int uid) {
        Log.d(TAG,"uid="+uid);
        VideoReportLayout videoContainer = getVideoLayoutByUid(uid);
        if (videoContainer == null) {
            videoContainer = getIdleVideoContainer();
        }
        if (videoContainer == null) {
            return null;
        }
        videoContainer.removeAllViews();
        SurfaceView videoView = new SurfaceView(getBaseContext());
        videoContainer.addView(videoView);
        videoContainer.setReportUid(uid);
        return videoView;

    }

    private VideoReportLayout getIdleVideoContainer() {
        for (VideoReportLayout frameLayout : flVideoContainer) {
            if (frameLayout.getReportUid() == -1) {
                return frameLayout;
            }
        }
        return null;
    }

    private void resetVideoLayout(int uid) {
        VideoReportLayout videoContainer = getVideoLayoutByUid(uid);
        if (videoContainer == null) {
            return;
        }
        videoContainer.removeAllViews();
        videoContainer.setReportUid(-1);
    }


    private VideoReportLayout getVideoLayoutByUid(int uid) {
        for (VideoReportLayout frameLayout : flVideoContainer) {
            if (frameLayout.getReportUid() == uid) {
                return frameLayout;
            }
        }
        return null;
    }



    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_surface_view_camera);
        findViewById(R.id.RelativeLayout1).setOnClickListener(mOnClickListener);
        mUSBMonitor = new USBMonitor(this, mOnDeviceConnectListener);
        initView();
        resultFirstCamera();
        resultSecondCamera();
        resultThirdCamera();
        resultFourthCamera();
        resultFifThCamrea();
        resultSixthCamera();
    }

    //声网添加控件初始化
    private void initView() {
        etChannelName = findViewById(R.id.et_channel_name);
        btnAdd = findViewById(R.id.btn_add);
        btnAdd.setOnClickListener(mOnClickListener);
        btnTrack = findViewById(R.id.btn_truck);
        btnTrack.setOnClickListener(mOnClickListener);
        flLocal = findViewById(R.id.local_video_view_container);

        flVideoContainer = new VideoReportLayout[]{
                findViewById(R.id.fl_video_container_01),
                findViewById(R.id.fl_video_container_02),
        };

        try {
            // 创建 RtcEngineConfig 对象，并进行配置
            RtcEngineConfig config = new RtcEngineConfig();
            config.mContext = getBaseContext();
            config.mAppId = getString(R.string.agora_app_id);
            config.mEventHandler = mRtcEventHandler;
            //设置音频场景以获取更好的音频效果
            config.mAudioScenario = Constants.AudioScenario.getValue(Constants.AudioScenario.CHATROOM);
            // 创建并初始化 RtcEngine
            mRtcEngine = (RtcEngineEx) RtcEngine.create(config);
        } catch (Exception e) {
            throw new RuntimeException("Check the error.");
        }
    }

    /**
     * 带有回调数据的初始化
     */
    private void resultFirstCamera() {
        mUVCCameraViewFirst = (CameraViewInterface) findViewById(R.id.camera_view_first);
        //设置显示宽高
        mUVCCameraViewFirst.setAspectRatio(UVCCamera.DEFAULT_PREVIEW_WIDTH / (float) UVCCamera.DEFAULT_PREVIEW_HEIGHT);
        ((UVCCameraTextureView) mUVCCameraViewFirst).setOnClickListener(mOnClickListener);
        mCaptureButtonFirst = (ImageButton) findViewById(R.id.capture_button_first);
        mCaptureButtonFirst.setOnClickListener(mOnClickListener);
        mCaptureButtonFirst.setVisibility(View.INVISIBLE);
        mHandlerFirst = UVCCameraHandler.createHandler(this, mUVCCameraViewFirst
                , UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT
                , BANDWIDTH_FACTORS[0], firstDataCallBack);
    }

    UvcCameraDataCallBack firstDataCallBack = new UvcCameraDataCallBack() {
        @Override
        public void getData(byte[] data, int width, int height) {
            if (DEBUG) Log.v(TAG, "数据回调11:" + data.length+",width="+width+",height="+height);
            //byte[] yuv, int width, int height
            mData = data;
            mWidth = width;
            mHeight = height;
            createPushingVideoTrack();
        }
    };

    private void resultSecondCamera() {
        mUVCCameraViewSecond = (CameraViewInterface) findViewById(R.id.camera_view_second);
        mUVCCameraViewSecond.setAspectRatio(UVCCamera.DEFAULT_PREVIEW_WIDTH / (float) UVCCamera.DEFAULT_PREVIEW_HEIGHT);
        ((UVCCameraTextureView) mUVCCameraViewSecond).setOnClickListener(mOnClickListener);
        mCaptureButtonSecond = (ImageButton) findViewById(R.id.capture_button_second);
        mCaptureButtonSecond.setOnClickListener(mOnClickListener);
        mCaptureButtonSecond.setVisibility(View.INVISIBLE);
        mHandlerSecond = UVCCameraHandler.createHandler(this, mUVCCameraViewSecond,
                UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT,
                BANDWIDTH_FACTORS[1],secondDataCallBack);
    }

    UvcCameraDataCallBack secondDataCallBack = new UvcCameraDataCallBack() {
        @Override
        public void getData(byte[] data, int width, int height) {
            if (DEBUG) Log.v(TAG, "数据回调22:" + data.length+",width="+width+",height="+height);
            //byte[] yuv, int width, int height
            mData1 = data;
            mWidth1 = width;
            mHeight1 = height;
            createPushingVideoTrack1();
        }
    };

    private void resultThirdCamera() {
        mUVCCameraViewThird = (CameraViewInterface) findViewById(R.id.camera_view_third);
        mUVCCameraViewThird.setAspectRatio(UVCCamera.DEFAULT_PREVIEW_WIDTH / (float) UVCCamera.DEFAULT_PREVIEW_HEIGHT);
        ((UVCCameraTextureView) mUVCCameraViewThird).setOnClickListener(mOnClickListener);
        mCaptureButtonThird = (ImageButton) findViewById(R.id.capture_button_third);
        mCaptureButtonThird.setOnClickListener(mOnClickListener);
        mCaptureButtonThird.setVisibility(View.INVISIBLE);
        mHandlerThird = UVCCameraHandler.createHandler(this, mUVCCameraViewThird, UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, BANDWIDTH_FACTORS[1]);
    }

    private void resultFourthCamera() {
        mUVCCameraViewFourth = (CameraViewInterface) findViewById(R.id.camera_view_fourth);
        mUVCCameraViewFourth.setAspectRatio(UVCCamera.DEFAULT_PREVIEW_WIDTH / (float) UVCCamera.DEFAULT_PREVIEW_HEIGHT);
        ((UVCCameraTextureView) mUVCCameraViewFourth).setOnClickListener(mOnClickListener);
        mCaptureButtonFourth = (ImageButton) findViewById(R.id.capture_button_fourth);
        mCaptureButtonFourth.setOnClickListener(mOnClickListener);
        mCaptureButtonFourth.setVisibility(View.INVISIBLE);
        mHandlerFourth = UVCCameraHandler.createHandler(this, mUVCCameraViewFourth, UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, BANDWIDTH_FACTORS[1]);
    }

    private void resultFifThCamrea() {
        mUVCCameraViewFifth = (CameraViewInterface) findViewById(R.id.camera_view_fifth);
        mUVCCameraViewFifth.setAspectRatio(UVCCamera.DEFAULT_PREVIEW_WIDTH / (float) UVCCamera.DEFAULT_PREVIEW_HEIGHT);
        ((UVCCameraTextureView) mUVCCameraViewFifth).setOnClickListener(mOnClickListener);
        mCaptureButtonFifth = (ImageButton) findViewById(R.id.capture_button_fifth);
        mCaptureButtonFifth.setOnClickListener(mOnClickListener);
        mCaptureButtonFifth.setVisibility(View.INVISIBLE);
        mHandlerFifth = UVCCameraHandler.createHandler(this, mUVCCameraViewFifth, UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, BANDWIDTH_FACTORS[1]);
    }

    private void resultSixthCamera() {
        mUVCCameraViewSixth = (CameraViewInterface) findViewById(R.id.camera_view_sixth);
        mUVCCameraViewSixth.setAspectRatio(UVCCamera.DEFAULT_PREVIEW_WIDTH / (float) UVCCamera.DEFAULT_PREVIEW_HEIGHT);
        ((UVCCameraTextureView) mUVCCameraViewSixth).setOnClickListener(mOnClickListener);
        mCaptureButtonSixth = (ImageButton) findViewById(R.id.capture_button_sixth);
        mCaptureButtonSixth.setOnClickListener(mOnClickListener);
        mCaptureButtonSixth.setVisibility(View.INVISIBLE);
        mHandlerSixth = UVCCameraHandler.createHandler(this, mUVCCameraViewSixth, UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, BANDWIDTH_FACTORS[1]);
    }

    @Override
    protected void onStart() {
        super.onStart();
        mUSBMonitor.register();
        if (mUVCCameraViewSecond != null)
            mUVCCameraViewSecond.onResume();
        if (mUVCCameraViewFirst != null)
            mUVCCameraViewFirst.onResume();
        if (mUVCCameraViewThird != null)
            mUVCCameraViewThird.onResume();
        if (mUVCCameraViewFourth != null)
            mUVCCameraViewFourth.onResume();
        if (mUVCCameraViewFifth != null)
            mUVCCameraViewFifth.onResume();
        if (mUVCCameraViewSixth != null)
            mUVCCameraViewSixth.onResume();
    }

    @Override
    protected void onStop() {
        mHandlerFirst.close();
        if (mUVCCameraViewFirst != null)
            mUVCCameraViewFirst.onPause();
        mCaptureButtonFirst.setVisibility(View.INVISIBLE);

        mHandlerSecond.close();
        if (mUVCCameraViewSecond != null)
            mUVCCameraViewSecond.onPause();
        mCaptureButtonSecond.setVisibility(View.INVISIBLE);

        mHandlerThird.close();
        if (mUVCCameraViewThird != null)
            mUVCCameraViewThird.onPause();
        mCaptureButtonThird.setVisibility(View.INVISIBLE);

        mHandlerFourth.close();
        if (mUVCCameraViewFourth != null)
            mUVCCameraViewFourth.onPause();
        mCaptureButtonFourth.setVisibility(View.INVISIBLE);

        mHandlerFifth.close();
        if (mUVCCameraViewFifth != null)
            mUVCCameraViewFifth.onPause();
        mCaptureButtonFifth.setVisibility(View.INVISIBLE);

        mHandlerSixth.close();
        if (mUVCCameraViewSixth != null)
            mUVCCameraViewSixth.onPause();
        mCaptureButtonSixth.setVisibility(View.INVISIBLE);

        mUSBMonitor.unregister();//usb管理器解绑
        super.onStop();
    }


    @Override
    protected void onDestroy() {
        if (mHandlerFirst != null) {
            mHandlerFirst = null;
        }

        if (mHandlerSecond != null) {
            mHandlerSecond = null;
        }

        if (mHandlerThird != null) {
            mHandlerThird = null;
        }

        if (mHandlerFourth != null) {
            mHandlerFourth = null;
        }

        if (mHandlerFifth != null) {
            mHandlerFifth = null;
        }

        if (mHandlerSixth != null) {
            mHandlerSixth = null;
        }

        if (mUSBMonitor != null) {
            mUSBMonitor.destroy();
            mUSBMonitor = null;
        }

        mUVCCameraViewFirst = null;
        mCaptureButtonFirst = null;

        mUVCCameraViewSecond = null;
        mCaptureButtonSecond = null;

        mUVCCameraViewThird = null;
        mCaptureButtonThird = null;

        mUVCCameraViewFourth = null;
        mCaptureButtonFourth = null;

        mUVCCameraViewFifth = null;
        mCaptureButtonFifth = null;

        mUVCCameraViewSixth = null;
        mCaptureButtonSixth = null;
        super.onDestroy();
    }

    private final View.OnClickListener mOnClickListener = new View.OnClickListener() {
        @Override
        public void onClick(final View view) {
            switch (view.getId()) {
                case R.id.btn_add:
                    if (btnAdd.getText().equals("加入会议")){
                        if (TextUtils.isEmpty(etChannelName.getText())){
                            Toast.makeText(MainActivity.this,"频道号不可为空",Toast.LENGTH_LONG).show();
                        } else {
                            btnAdd.setText("退出会议");
                            hideSoftKeyboard(view);
                            // 如果已经授权，则初始化 RtcEngine 并加入频道
                            if (checkSelfPermission(REQUESTED_PERMISSIONS[0], PERMISSION_REQ_ID) &&
                                    checkSelfPermission(REQUESTED_PERMISSIONS[1], PERMISSION_REQ_ID)) {
                                joinChannel(etChannelName.getText().toString());

                            }
                        }
                    } else {
                        // 停止本地视频预览
                        mRtcEngine.stopPreview();
                        mRtcEngine.leaveChannel();
                        btnAdd.setText("加入会议");
                        flLocal.removeAllViews();
                    }


                    break;
                case R.id.btn_truck:
                        isFirst = true;
                        isFirst1 = true;
                        createPushingVideoTrack();
                        break;
                case R.id.camera_view_first:
                    if (mHandlerFirst != null) {
                        if (!mHandlerFirst.isOpened()) {
                            CameraDialog.showDialog(MainActivity.this);
                        } else {
                            mHandlerFirst.close();
                            setCameraButton();
                        }
                    }
                    break;
                case R.id.capture_button_first:
                    if (mHandlerFirst != null) {
                        if (mHandlerFirst.isOpened()) {
                            if (checkPermissionWriteExternalStorage() && checkPermissionAudio()) {
                                if (!mHandlerFirst.isRecording()) {
                                    mCaptureButtonFirst.setColorFilter(0xffff0000);    // turn red
                                    mHandlerFirst.startRecording();
                                } else {
                                    mCaptureButtonFirst.setColorFilter(0);    // return to default color
                                    mHandlerFirst.stopRecording();
                                }
                            }
                        }
                    }
                    break;
                case R.id.camera_view_second:
                    if (mHandlerSecond != null) {
                        if (!mHandlerSecond.isOpened()) {
                            CameraDialog.showDialog(MainActivity.this);
                        } else {
                            mHandlerSecond.close();
                            setCameraButton();
                        }
                    }
                    break;
                case R.id.capture_button_second:
                    if (mHandlerSecond != null) {
                        if (mHandlerSecond.isOpened()) {
                            if (checkPermissionWriteExternalStorage() && checkPermissionAudio()) {
                                if (!mHandlerSecond.isRecording()) {
                                    mCaptureButtonSecond.setColorFilter(0xffff0000);    // turn red
                                    mHandlerSecond.startRecording();
                                } else {
                                    mCaptureButtonSecond.setColorFilter(0);    // return to default color
                                    mHandlerSecond.stopRecording();
                                }
                            }
                        }
                    }
                    break;
                case R.id.camera_view_third:
                    if (mHandlerThird != null) {
                        if (!mHandlerThird.isOpened()) {
                            CameraDialog.showDialog(MainActivity.this);
                        } else {
                            mHandlerThird.close();
                            setCameraButton();
                        }
                    }
                    break;
                case R.id.capture_button_third:
                    if (mHandlerThird != null) {
                        if (mHandlerThird.isOpened()) {
                            if (checkPermissionWriteExternalStorage() && checkPermissionAudio()) {
                                if (!mHandlerThird.isRecording()) {
                                    mCaptureButtonThird.setColorFilter(0xffff0000);    // turn red
                                    mHandlerThird.startRecording();
                                } else {
                                    mCaptureButtonThird.setColorFilter(0);    // return to default color
                                    mHandlerThird.stopRecording();
                                }
                            }
                        }
                    }
                    break;
                case R.id.camera_view_fourth:
                    if (mHandlerFourth != null) {
                        if (!mHandlerFourth.isOpened()) {
                            CameraDialog.showDialog(MainActivity.this);
                        } else {
                            mHandlerFourth.close();
                            setCameraButton();
                        }
                    }
                    break;
                case R.id.capture_button_fourth:
                    if (mHandlerFourth != null) {
                        if (mHandlerFourth.isOpened()) {
                            if (checkPermissionWriteExternalStorage() && checkPermissionAudio()) {
                                if (!mHandlerFourth.isRecording()) {
                                    mCaptureButtonFourth.setColorFilter(0xffff0000);    // turn red
                                    mHandlerFourth.startRecording();
                                } else {
                                    mCaptureButtonFourth.setColorFilter(0);    // return to default color
                                    mHandlerFourth.stopRecording();
                                }
                            }
                        }
                    }
                    break;

                case R.id.camera_view_fifth:
                    if (mHandlerFifth != null) {
                        if (!mHandlerFifth.isOpened()) {
                            CameraDialog.showDialog(MainActivity.this);
                        } else {
                            mHandlerFifth.close();
                            setCameraButton();
                        }
                    }
                    break;
                case R.id.capture_button_fifth:
                    if (mHandlerFifth != null) {
                        if (mHandlerFifth.isOpened()) {
                            if (checkPermissionWriteExternalStorage() && checkPermissionAudio()) {
                                if (!mHandlerFifth.isRecording()) {
                                    mCaptureButtonFifth.setColorFilter(0xffff0000);    // turn red
                                    mHandlerFifth.startRecording();
                                } else {
                                    mCaptureButtonFifth.setColorFilter(0);    // return to default color
                                    mHandlerFifth.stopRecording();
                                }
                            }
                        }
                    }
                    break;

                case R.id.camera_view_sixth:
                    if (mHandlerSixth != null) {
                        if (!mHandlerSixth.isOpened()) {
                            CameraDialog.showDialog(MainActivity.this);
                        } else {
                            mHandlerSixth.close();
                            setCameraButton();
                        }
                    }
                    break;
                case R.id.capture_button_sixth:
                    if (mHandlerSixth != null) {
                        if (mHandlerSixth.isOpened()) {
                            if (checkPermissionWriteExternalStorage() && checkPermissionAudio()) {
                                if (!mHandlerSixth.isRecording()) {
                                    mCaptureButtonSixth.setColorFilter(0xffff0000);    // turn red
                                    mHandlerSixth.startRecording();
                                } else {
                                    mCaptureButtonSixth.setColorFilter(0);    // return to default color
                                    mHandlerSixth.stopRecording();
                                }
                            }
                        }
                    }
                    break;
            }
        }
    };

    //创建视频轨道
    private void createPushingVideoTrack() {
        if (isFirst){
            if (!joined || videoTrackIds.size() >= 4) {
                return;
            }

            /*
             * Get an custom video track id created by internal,which could used to publish or preview
             *
             * @return
             * - > 0: the useable video track id.
             * - < 0: Failure.
             */
            videoTrack = mRtcEngine.createCustomVideoTrack();
            if (videoTrack < 0) {
                Toast.makeText(this, "createCustomVideoTrack failed!", Toast.LENGTH_LONG).show();
                return;
            }

            String channelId = etChannelName.getText().toString();
            int uid = new Random().nextInt(1000) + 20000;
            RtcConnection connection = new RtcConnection(channelId, uid);


            ChannelMediaOptions option = new ChannelMediaOptions();
            option.clientRoleType = Constants.CLIENT_ROLE_BROADCASTER;
            option.autoSubscribeAudio = false;
            option.autoSubscribeVideo = false;
            option.publishCustomVideoTrack = true;
            option.publishCameraTrack = false;
            /*
            specify custom video track id to publish in this channel.
             */
            option.customVideoTrackId = videoTrack;

            int res = mRtcEngine.joinChannelEx(token, connection, option, new IRtcEngineEventHandler() {
            });
            Log.e(TAG,"res=="+res);
            if (res != 0) {
                /*
                 * destroy a created custom video track id
                 *
                 * @param video_track_id The video track id which was created by createCustomVideoTrack
                 * @return
                 * - 0: Success.
                 * - < 0: Failure.
                 */
                mRtcEngine.destroyCustomVideoTrack(videoTrack);
                Log.e(TAG,RtcEngine.getErrorDescription(Math.abs(res)));
            } else {
                if (DEBUG) Log.v(TAG, "数据回调1122:" + mData.length+",width="+mWidth+",height="+mHeight);
                isFirst = false;
                if (joined && mRtcEngine != null){
                    VideoFrame.Buffer frameBuffer;
                    // I420 type default
                    JavaI420Buffer i420Buffer = JavaI420Buffer.allocate(mWidth, mHeight);
                    i420Buffer.getDataY().put(mData, 0, i420Buffer.getDataY().limit());
                    i420Buffer.getDataU().put(mData, i420Buffer.getDataY().limit(), i420Buffer.getDataU().limit());
                    i420Buffer.getDataV().put(mData, i420Buffer.getDataY().limit() + i420Buffer.getDataU().limit(), i420Buffer.getDataV().limit());
                    frameBuffer = i420Buffer;
                    /*
                     * Get monotonic time in ms which can be used by capture time,
                     * typical scenario is as follows:
                     */
                    long currentMonotonicTimeInMs = mRtcEngine.getCurrentMonotonicTimeInMs();
                    /*
                     * Create a video frame to push.
                     */
                    VideoFrame videoFrame = new VideoFrame(frameBuffer, 0, currentMonotonicTimeInMs * 1000000);

                    /*
                     * Pushes the external video frame to the app.
                     *
                     * @param frame The external video frame: ExternalVideoFrame.
                     * @param videoTrackId The id of the video track.
                     * - 0: Success.
                     * - < 0: Failure.
                     */
                    int ret = mRtcEngine.pushExternalVideoFrameEx(videoFrame, videoTrack);
                    // 推送成功后，释放 i420Buffer 对象占用的内存资源
                    i420Buffer.release();
                    if (ret < 0) {
                        Log.w(TAG, "pushExternalVideoFrameEx error code=" + ret);
                    }
                }

                /*
                 * cache video track ids , video file readers and rtc connection to release while fragment destroying.
                 */
                videoTrackIds.add(videoTrack);
                connections.add(connection);
            }
        } else {
            if (DEBUG) Log.v(TAG, "数据回调112233:" + mData.length+",width="+mWidth+",height="+mHeight+",videoTrack="+videoTrack);
            if (joined && mRtcEngine != null){
                VideoFrame.Buffer frameBuffer;
                // I420 type default
                JavaI420Buffer i420Buffer = JavaI420Buffer.allocate(mWidth, mHeight);
                i420Buffer.getDataY().put(mData, 0, i420Buffer.getDataY().limit());
                i420Buffer.getDataU().put(mData, i420Buffer.getDataY().limit(), i420Buffer.getDataU().limit());
                i420Buffer.getDataV().put(mData, i420Buffer.getDataY().limit() + i420Buffer.getDataU().limit(), i420Buffer.getDataV().limit());
                frameBuffer = i420Buffer;
                /*
                 * Get monotonic time in ms which can be used by capture time,
                 * typical scenario is as follows:
                 */
                long currentMonotonicTimeInMs = mRtcEngine.getCurrentMonotonicTimeInMs();
                /*
                 * Create a video frame to push.
                 */
                VideoFrame videoFrame = new VideoFrame(frameBuffer, 0, currentMonotonicTimeInMs * 1000000);

                /*
                 * Pushes the external video frame to the app.
                 *
                 * @param frame The external video frame: ExternalVideoFrame.
                 * @param videoTrackId The id of the video track.
                 * - 0: Success.
                 * - < 0: Failure.
                 */
                int ret = mRtcEngine.pushExternalVideoFrameEx(videoFrame, videoTrack);
                // 推送成功后，释放 i420Buffer 对象占用的内存资源
                i420Buffer.release();
                if (ret < 0) {
                    Log.w(TAG, "pushExternalVideoFrameEx error code=" + ret);
                }
            }
        }

    }

    private void createPushingVideoTrack1() {
        if (isFirst1){
            if (!joined || videoTrackIds.size() >= 4) {
                return;
            }

            /*
             * Get an custom video track id created by internal,which could used to publish or preview
             *
             * @return
             * - > 0: the useable video track id.
             * - < 0: Failure.
             */
            videoTrack1 = mRtcEngine.createCustomVideoTrack();
            if (videoTrack1 < 0) {
                Toast.makeText(this, "createCustomVideoTrack failed!", Toast.LENGTH_LONG).show();
                return;
            }

            String channelId = etChannelName.getText().toString();
            int uid = new Random().nextInt(1000) + 20000;
            RtcConnection connection = new RtcConnection(channelId, uid);


            ChannelMediaOptions option = new ChannelMediaOptions();
            option.clientRoleType = Constants.CLIENT_ROLE_BROADCASTER;
            option.autoSubscribeAudio = false;
            option.autoSubscribeVideo = false;
            option.publishCustomVideoTrack = true;
            option.publishCameraTrack = false;
            /*
            specify custom video track id to publish in this channel.
             */
            option.customVideoTrackId = videoTrack1;

            int res = mRtcEngine.joinChannelEx(token, connection, option, new IRtcEngineEventHandler() {
            });
            Log.e(TAG,"res=="+res);
            if (res != 0) {
                /*
                 * destroy a created custom video track id
                 *
                 * @param video_track_id The video track id which was created by createCustomVideoTrack
                 * @return
                 * - 0: Success.
                 * - < 0: Failure.
                 */
                mRtcEngine.destroyCustomVideoTrack(videoTrack1);
                Log.e(TAG,RtcEngine.getErrorDescription(Math.abs(res)));
            } else {
                if (DEBUG) Log.v(TAG, "数据回调112233:" + mData1.length+",width="+mWidth1+",height="+mHeight1);
                isFirst1 = false;
                if (joined && mRtcEngine != null){
                    VideoFrame.Buffer frameBuffer;
                    // I420 type default
                    JavaI420Buffer i420Buffer = JavaI420Buffer.allocate(mWidth1, mHeight1);
                    i420Buffer.getDataY().put(mData1, 0, i420Buffer.getDataY().limit());
                    i420Buffer.getDataU().put(mData1, i420Buffer.getDataY().limit(), i420Buffer.getDataU().limit());
                    i420Buffer.getDataV().put(mData1, i420Buffer.getDataY().limit() + i420Buffer.getDataU().limit(), i420Buffer.getDataV().limit());
                    frameBuffer = i420Buffer;
                    /*
                     * Get monotonic time in ms which can be used by capture time,
                     * typical scenario is as follows:
                     */
                    long currentMonotonicTimeInMs = mRtcEngine.getCurrentMonotonicTimeInMs();
                    /*
                     * Create a video frame to push.
                     */
                    VideoFrame videoFrame = new VideoFrame(frameBuffer, 0, currentMonotonicTimeInMs * 1000000);

                    /*
                     * Pushes the external video frame to the app.
                     *
                     * @param frame The external video frame: ExternalVideoFrame.
                     * @param videoTrackId The id of the video track.
                     * - 0: Success.
                     * - < 0: Failure.
                     */
                    int ret = mRtcEngine.pushExternalVideoFrameEx(videoFrame, videoTrack1);
                    // 推送成功后，释放 i420Buffer 对象占用的内存资源
                    i420Buffer.release();
                    if (ret < 0) {
                        Log.w(TAG, "pushExternalVideoFrameEx error code=" + ret);
                    }
                }

                /*
                 * cache video track ids , video file readers and rtc connection to release while fragment destroying.
                 */
                videoTrackIds.add(videoTrack1);
                connections.add(connection);
            }
        } else {
            if (DEBUG) Log.v(TAG, "数据回调11223344:" + mData1.length+",width="+mWidth1+",height="+mHeight1+",videoTrack1="+videoTrack1);
            if (joined && mRtcEngine != null){
                VideoFrame.Buffer frameBuffer;
                // I420 type default
                JavaI420Buffer i420Buffer = JavaI420Buffer.allocate(mWidth1, mHeight1);
                i420Buffer.getDataY().put(mData1, 0, i420Buffer.getDataY().limit());
                i420Buffer.getDataU().put(mData1, i420Buffer.getDataY().limit(), i420Buffer.getDataU().limit());
                i420Buffer.getDataV().put(mData1, i420Buffer.getDataY().limit() + i420Buffer.getDataU().limit(), i420Buffer.getDataV().limit());
                frameBuffer = i420Buffer;
                /*
                 * Get monotonic time in ms which can be used by capture time,
                 * typical scenario is as follows:
                 */
                long currentMonotonicTimeInMs = mRtcEngine.getCurrentMonotonicTimeInMs();
                /*
                 * Create a video frame to push.
                 */
                VideoFrame videoFrame = new VideoFrame(frameBuffer, 0, currentMonotonicTimeInMs * 1000000);

                /*
                 * Pushes the external video frame to the app.
                 *
                 * @param frame The external video frame: ExternalVideoFrame.
                 * @param videoTrackId The id of the video track.
                 * - 0: Success.
                 * - < 0: Failure.
                 */
                int ret = mRtcEngine.pushExternalVideoFrameEx(videoFrame, videoTrack1);
                // 推送成功后，释放 i420Buffer 对象占用的内存资源
                i420Buffer.release();
                if (ret < 0) {
                    Log.w(TAG, "pushExternalVideoFrameEx error code=" + ret);
                }
            }
        }

    }

    //初始化并加入
    private void joinChannel(String channelName) {
        // 启用视频模块
        mRtcEngine.enableVideo();
        // 开启本地预览
        mRtcEngine.startPreview();

        SurfaceView surfaceView = new SurfaceView (getBaseContext());
        flLocal.addView(surfaceView);
        // 将 SurfaceView 对象传入声网实时互动 SDK，设置本地视图
        mRtcEngine.setupLocalVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_HIDDEN, 0));

        // 创建 ChannelMediaOptions 对象，并进行配置
        ChannelMediaOptions options = new ChannelMediaOptions();
        // 根据场景将用户角色设置为 BROADCASTER (主播) 或 AUDIENCE (观众)
        options.clientRoleType = Constants.CLIENT_ROLE_BROADCASTER;
        // 直播场景下，设置频道场景为 BROADCASTING (直播场景)
        options.channelProfile = Constants.CHANNEL_PROFILE_LIVE_BROADCASTING;
        options.autoSubscribeAudio = true;
        options.autoSubscribeVideo = true;
        options.publishMicrophoneTrack = true;
        options.publishCameraTrack = true;

        // 使用临时 Token 加入频道，自行指定用户 ID 并确保其在频道内的唯一性
        mRtcEngine.joinChannel(token, channelName, 0, options);
    }

    public void hideSoftKeyboard(View view) {
        // 步骤一：获取当前焦点的View
        View currentFocus = this.getCurrentFocus();

        // 步骤二：创建InputMethodManager对象
        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);

        // 步骤三：关闭软键盘
        imm.hideSoftInputFromWindow(currentFocus.getWindowToken(), 0);
    }

    private final OnDeviceConnectListener mOnDeviceConnectListener = new OnDeviceConnectListener() {
        @Override
        public void onAttach(final UsbDevice device) {
            if (DEBUG) Log.v(TAG, "onAttach:" + device);
            //onAttach:UsbDevice[mName=/dev/bus/usb/004/003,mVendorId=3034,mProductId=33107,
            // mClass=0,mSubclass=0,mProtocol=0,mManufacturerName=Realtek,
            // mProductName=USB 10/100/1000 LAN,mVersion=31.01,
            // mSerialNumberReader=android.hardware.usb.IUsbSerialReader$Stub$Proxy@d073b0a


            //onAttach:UsbDevice[mName=/dev/bus/usb/005/033,mVendorId=13297,mProductId=4096,
            // mClass=239,mSubclass=2,mProtocol=1,mManufacturerName=Linux
            // Foundation,mProductName=HD Camera,mVersion=4.09,
            // mSerialNumberReader=android.hardware.usb.IUsbSerialReader$Stub$Proxy@3cd5f7b,
            // mHasAudioPlayback=true, mHasAudioCapture=true


            Toast.makeText(MainActivity.this, "USB_DEVICE_ATTACHED", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onConnect(final UsbDevice device, final UsbControlBlock ctrlBlock, final boolean createNew) {
            //设备连接成功
            if (DEBUG) Log.v(TAG, "onConnect:" + device);
            if (!mHandlerFirst.isOpened()) {
                mHandlerFirst.open(ctrlBlock);
                final SurfaceTexture st = mUVCCameraViewFirst.getSurfaceTexture();
                mHandlerFirst.startPreview(new Surface(st));

                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mCaptureButtonFirst.setVisibility(View.VISIBLE);
                    }
                });
            } else if (!mHandlerSecond.isOpened()) {
                mHandlerSecond.open(ctrlBlock);
                final SurfaceTexture st = mUVCCameraViewSecond.getSurfaceTexture();
                mHandlerSecond.startPreview(new Surface(st));
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mCaptureButtonSecond.setVisibility(View.VISIBLE);
                    }
                });
            } else if (!mHandlerThird.isOpened()) {
                mHandlerThird.open(ctrlBlock);
                final SurfaceTexture st = mUVCCameraViewThird.getSurfaceTexture();
                mHandlerThird.startPreview(new Surface(st));
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mCaptureButtonThird.setVisibility(View.VISIBLE);
                    }
                });
            } else if (!mHandlerFourth.isOpened()) {
                mHandlerFourth.open(ctrlBlock);
                final SurfaceTexture st = mUVCCameraViewFourth.getSurfaceTexture();
                mHandlerFourth.startPreview(new Surface(st));
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mCaptureButtonFourth.setVisibility(View.VISIBLE);
                    }
                });
            } else if (!mHandlerFifth.isOpened()) {
                mHandlerFifth.open(ctrlBlock);
                final SurfaceTexture st = mUVCCameraViewFifth.getSurfaceTexture();
                mHandlerFifth.startPreview(new Surface(st));
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mCaptureButtonFifth.setVisibility(View.VISIBLE);
                    }
                });
            } else if (!mHandlerSixth.isOpened()) {
                mHandlerSixth.open(ctrlBlock);
                final SurfaceTexture st = mUVCCameraViewSixth.getSurfaceTexture();
                mHandlerSixth.startPreview(new Surface(st));
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mCaptureButtonSixth.setVisibility(View.VISIBLE);
                    }
                });
            }
        }

        @Override
        public void onDisconnect(final UsbDevice device, final UsbControlBlock ctrlBlock) {
            if (DEBUG) Log.v(TAG, "onDisconnect:" + device);
            if ((mHandlerFirst != null) && !mHandlerFirst.isEqual(device)) {
                queueEvent(new Runnable() {
                    @Override
                    public void run() {
                        mHandlerFirst.close();
                        if (mFirstPreviewSurface != null) {
                            mFirstPreviewSurface.release();
                            mFirstPreviewSurface = null;
                        }
                        setCameraButton();
                    }
                }, 0);
            } else if ((mHandlerSecond != null) && !mHandlerSecond.isEqual(device)) {
                queueEvent(new Runnable() {
                    @Override
                    public void run() {
                        mHandlerSecond.close();
                        if (mSecondPreviewSurface != null) {
                            mSecondPreviewSurface.release();
                            mSecondPreviewSurface = null;
                        }
                        setCameraButton();
                    }
                }, 0);
            } else if ((mHandlerThird != null) && !mHandlerThird.isEqual(device)) {
                queueEvent(new Runnable() {
                    @Override
                    public void run() {
                        mHandlerThird.close();
                        if (mThirdPreviewSurface != null) {
                            mThirdPreviewSurface.release();
                            mThirdPreviewSurface = null;
                        }
                        setCameraButton();
                    }
                }, 0);
            } else if ((mHandlerFourth != null) && !mHandlerFourth.isEqual(device)) {
                queueEvent(new Runnable() {
                    @Override
                    public void run() {
                        mHandlerFourth.close();
                        if (mFourthPreviewSurface != null) {
                            mFourthPreviewSurface.release();
                            mFourthPreviewSurface = null;
                        }
                        setCameraButton();
                    }
                }, 0);
            } else if ((mHandlerFifth != null) && !mHandlerFifth.isEqual(device)) {
                queueEvent(new Runnable() {
                    @Override
                    public void run() {
                        mHandlerFifth.close();
                        if (mFifthPreviewSurface != null) {
                            mFifthPreviewSurface.release();
                            mFifthPreviewSurface = null;
                        }
                        setCameraButton();
                    }
                }, 0);
            } else if ((mHandlerSixth != null) && !mHandlerSixth.isEqual(device)) {
                queueEvent(new Runnable() {
                    @Override
                    public void run() {
                        mHandlerSixth.close();
                        if (mSixthPreviewSurface != null) {
                            mSixthPreviewSurface.release();
                            mSixthPreviewSurface = null;
                        }
                        setCameraButton();
                    }
                }, 0);
            }
        }

        @Override
        public void onDettach(final UsbDevice device) {
            if (DEBUG) Log.v(TAG, "onDettach:" + device);
            Toast.makeText(MainActivity.this, "USB_DEVICE_DETACHED", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onCancel(final UsbDevice device) {
            if (DEBUG) Log.v(TAG, "onCancel:");
        }
    };

    /**
     * to access from CameraDialog
     *
     * @return
     */
    @Override
    public USBMonitor getUSBMonitor() {
        return mUSBMonitor;
    }

    @Override
    public void onDialogResult(boolean canceled) {
        if (canceled) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    setCameraButton();
                }
            }, 0);
        }
    }

    private void setCameraButton() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if ((mHandlerFirst != null) && !mHandlerFirst.isOpened() && (mCaptureButtonFirst != null)) {
                    mCaptureButtonFirst.setVisibility(View.INVISIBLE);
                }
                if ((mHandlerSecond != null) && !mHandlerSecond.isOpened() && (mCaptureButtonSecond != null)) {
                    mCaptureButtonSecond.setVisibility(View.INVISIBLE);
                }
                if ((mHandlerThird != null) && !mHandlerThird.isOpened() && (mCaptureButtonThird != null)) {
                    mCaptureButtonThird.setVisibility(View.INVISIBLE);
                }
                if ((mHandlerFourth != null) && !mHandlerFourth.isOpened() && (mCaptureButtonFourth != null)) {
                    mCaptureButtonFourth.setVisibility(View.INVISIBLE);
                }
                if ((mHandlerFifth != null) && !mHandlerFifth.isOpened() && (mCaptureButtonFifth != null)) {
                    mCaptureButtonFifth.setVisibility(View.INVISIBLE);
                }
                if ((mHandlerSixth != null) && !mHandlerSixth.isOpened() && (mCaptureButtonSixth != null)) {
                    mCaptureButtonSixth.setVisibility(View.INVISIBLE);
                }
            }
        }, 0);
    }
}
